from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from lxml import etree
from PIL import Image 
import requests
import datetime
import random
import time
import sys
import os

class Geecheck():
    def __init__(self):
        self.un = '18361701417'
        # self.un = '18361598183'
        self.pw = '654321'
        self.url_login = 'https://36kr.com/'
        self.year = time.strftime('%Y')
        self.month = time.strftime('%m')
        self.day = time.strftime('%d')
        chrome_options = Options()
        self.domore = 1
        chrome_options.add_argument('--no-sandbox')
        chrome_options.add_argument('--start-maximized')
        # chrome_options.add_argument('--headless')
        self.browser = webdriver.Chrome(chrome_options=chrome_options)
        time.sleep(5)

    def login(self):
        browser = self.browser
        browser.get(self.url_login)
        time.sleep(10)
        print('开始登录……当前网址：{}'.format(browser.current_url))
        wait = WebDriverWait(browser, 10)
        bt_resgister = wait.until(EC.visibility_of_element_located((
                                        By.XPATH,
                                        '//a[@class="resgister"]'
                                        )))
        bt_resgister.click()
        time.sleep(2)
        phone = wait.until(EC.visibility_of_element_located((
                                        By.XPATH,
                                        '//div/input[@class="number"]'
                                        )))
        ps = wait.until(EC.visibility_of_element_located((
                                        By.XPATH,
                                        '//div/input[@class="password"]'
                                        )))
        phone.send_keys(self.un)
        time.sleep(random.randint(1, 3))
        ps.send_keys(self.pw)
        time.sleep(random.randint(1, 3))
        bn_yzm = wait.until(EC.visibility_of_element_located((
                                        By.XPATH,
                                        '//div[@class="send-normal-code active"]'
                                        )))
        time.sleep(1)
        bn_yzm.click()
        time.sleep(5)

    def check_geetest(self):
        browser = self.browser
        wait = WebDriverWait(browser, 10)
        while self.domore > 0:
            img_bg_ele = wait.until(EC.visibility_of_element_located((
                                            By.XPATH,
                                            '//canvas[@class="geetest_canvas_bg geetest_absolute"]'
                                            )))
            self.get_geetest_img(self.get_position(img_bg_ele), 'bg_que.png')
            print('获取缺图')
            js_show_fullbg = 'document.getElementsByClassName("geetest_canvas_fullbg geetest_fade geetest_absolute")[0].style.display="block";document.getElementsByClassName("geetest_canvas_fullbg geetest_fade geetest_absolute")[0].style.opacity="1";'
            js_hide_fullbg = 'document.getElementsByClassName("geetest_canvas_fullbg geetest_fade geetest_absolute")[0].style.display="none";'
            browser.execute_script(js_show_fullbg)
            print('显示全底图')
            img_fullbg_ele = wait.until(EC.visibility_of_element_located((
                                            By.XPATH,
                                            '//canvas[@class="geetest_canvas_fullbg geetest_fade geetest_absolute"]'
                                        )))
            self.get_geetest_img(self.get_position(img_fullbg_ele), 'bg_full.png')
            print('获取全图')
            time.sleep(1)
            browser.execute_script(js_hide_fullbg)
            time.sleep(1)
            slider_ele = wait.until(EC.visibility_of_element_located((
                                        By.XPATH,
                                        '//div[@class="geetest_slider_button"]'
                                        )))
            distance = self.get_distance('bg_que.png', 'bg_full.png')
            print('滑动距离', distance)
            tracks = self.get_track(distance-7)
            self.move_slider(tracks, slider_ele)
            print('移动操作完成！！！')
            time.sleep(1)
            div_panel_next = browser.find_element(
                                        By.XPATH,
                                        '//div[@class="geetest_panel_next"]'
                                        )
            if div_panel_next.is_displayed():
                print('验证失败……重新开始！')
                self.domore += 1
                if self.domore > 5:
                    self.domore = 0
                    print('重试次数太多，退出……')
                    break
            else:
                self.domore = 0
                print('验证通过！')
                break
            time.sleep(5)
        time.sleep(15)
        browser.close()

    def get_position(self, img_ele):
        location = img_ele.location
        size = img_ele.size
        left, top, right, bottom = location['x'], location['y'], location['x'] + size['width'], location['y']  + size['height']
        return (left, top, right, bottom)

    def get_geetest_img(self, position, img_name):
        browser = self.browser
        browser.get_screenshot_as_file('big.png')
        im = Image.open('big.png')
        captcha=im.crop(position)
        captcha.save(img_name, 'PNG') 
        print('截取图片')

    def get_distance(self, image_name1, image_name2):
        '''
        拿到滑动验证码需要移动的距离
        :param image_name1:没有缺口的图片对象
        :param image_name2:带缺口的图片对象
        :return:需要移动的距离
        '''
        threshold=60
        left=60
        image1 = Image.open(image_name1)
        image2 = Image.open(image_name2)
        for i in range(left,image1.size[0]):
            for j in range(image1.size[1]):
                rgb1=image1.load()[i,j]
                rgb2=image2.load()[i,j]
                res1=abs(rgb1[0]-rgb2[0])
                res2=abs(rgb1[1]-rgb2[1])
                res3=abs(rgb1[2]-rgb2[2])
                if not (res1 < threshold and res2 < threshold and res3 < threshold):
                    return i
        return i

    def get_track(self, distance):
        v = 0
        t = 0.3
        tracks = []
        current = 0
        mid = distance * 4 / 5
        while current < distance:
            if current < mid:
                a = 5 
            else:
                a = -3
            v0 = v
            s = v0 * t + 0.5 * a * (t ** 2)
            current += s
            tracks.append(round(s))
            v = v0 + a*t
        return tracks

    def move_slider(self, tracks, slider):
        ActionChains(self.browser).click_and_hold(slider).perform()
        for track in tracks:
            ActionChains(self.browser).move_by_offset(xoffset=track, yoffset=0).perform()
        ActionChains(self.browser).move_by_offset(xoffset=1, yoffset=0).perform()
        ActionChains(self.browser).move_by_offset(xoffset=-1, yoffset=0).perform()
        time.sleep(0.3)
        ActionChains(self.browser).release().perform()


if __name__ == '__main__':
    GC = Geecheck()
    GC.login()
    GC.check_geetest()
